package com.maiji.cloud.service.impl;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.maiji.cloud.entities.login.UserInfo;
import com.maiji.cloud.microservice.UserInfoService;
import com.maiji.cloud.request.ReqMetaData;
import com.maiji.cloud.request.shopingmall.DbApplyExamineReqData;
import com.maiji.cloud.request.shopingmall.DbApplyInfoReqData;
import com.maiji.cloud.response.*;
import com.maiji.cloud.service.CapitalMainService;
import com.maiji.cloud.utils.*;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import com.alibaba.fastjson.JSON;
import com.maiji.cloud.config.MyRedisConfig;
import com.maiji.cloud.entities.login.AppUser;
import com.maiji.cloud.entities.shopingmall.CapitalMain;
import com.maiji.cloud.entities.shopingmall.DistributionAgentApplyEntity;
import com.maiji.cloud.entities.shopingmall.DistributionFundRuleEntity;
import com.maiji.cloud.entities.shopingmall.DistributionLogEntity;
import com.maiji.cloud.entities.shopingmall.ShopingOrder;
import com.maiji.cloud.mapper.CapitalMainMapper;
import com.maiji.cloud.mapper.DistributionAgentApplyMapper;
import com.maiji.cloud.mapper.DistributionLogMapper;
import com.maiji.cloud.mapper.ShopingOrderMapper;
import com.maiji.cloud.request.BaseDataReqDto;
import com.maiji.cloud.request.BaseInputDto;
import com.maiji.cloud.request.IdInputDto;
import com.maiji.cloud.request.shopingmall.DistributionLogListReqDto;
import com.maiji.cloud.request.shopingmall.SubmitApplayReqData;
import com.maiji.cloud.response.login.UserInfoResDto;
import com.maiji.cloud.response.shopingmall.DistributionAgentApplyInfoResData;
import com.maiji.cloud.response.shopingmall.DistributionLogListResData;
import com.maiji.cloud.response.shopingmall.DistributionLogListResDto;
import com.maiji.cloud.service.AppLoginFeignService;
import com.maiji.cloud.service.DistributionService;

@Service
@Transactional
public class DistributionServiceImpl extends ServiceImpl<DistributionAgentApplyMapper, DistributionAgentApplyEntity> implements DistributionService {

	Logger logger = LoggerFactory.getLogger(DistributionServiceImpl.class);
	@Autowired
	private DistributionAgentApplyMapper distributionAgentApplyMapper;
	@Autowired
	private RedisTemplate<String, Object> redisTemplate;
	@Autowired
	private DistributionLogMapper distributionLogMapper;
	@Autowired
	private AppLoginFeignService appLoginFeignService;
	@Autowired
	private ShopingOrderMapper shopingOrderMapper;
	@Autowired
	private MongoTemplate mongoTemplate;
	@Autowired
	private CapitalMainMapper capitalMainMapper;
	@Autowired
	private CapitalMainService capitalMainService;
	@Autowired
	private UserInfoService userInfoService;
	 @Value("${realmName}")
	private String realmName;

	@Override
	public BaseResDto submitApplay(BaseDataReqDto<SubmitApplayReqData> param, String maijiToken) {
		logger.info("DistributionServiceImpl.submitApplay,param is {}", JSON.toJSONString(param));
		AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, maijiToken, userInfoService);
		DistributionAgentApplyEntity distributionAgentApplyEntity = distributionAgentApplyMapper
				.selectById(appUser.getUuId());
		if (distributionAgentApplyEntity != null) {
			BeanUtils.copyProperties(param.getData(), distributionAgentApplyEntity);
			distributionAgentApplyEntity.setStatus(CommonIntValueEnum.DISTRIBUTION_AGENT_APPLY_STATUS_AUDIT.getValue());
			distributionAgentApplyMapper.updateById(distributionAgentApplyEntity);
			return new BaseResDto(Status.SUCCESS);
		}
		distributionAgentApplyEntity = new DistributionAgentApplyEntity();
		BeanUtils.copyProperties(param.getData(), distributionAgentApplyEntity);
		distributionAgentApplyEntity.setUuId(appUser.getUuId());
		distributionAgentApplyEntity.setInTime(new Date());
		distributionAgentApplyEntity.setStatus(CommonIntValueEnum.DISTRIBUTION_AGENT_APPLY_STATUS_AUDIT.getValue());

		distributionAgentApplyMapper.insert(distributionAgentApplyEntity);

		return new BaseResDto(Status.SUCCESS);
	}

	@Override
	public Double getDistributionSumMoney(DistributionLogListReqDto param, String maijiToken) {
		logger.info("DistributionServiceImpl.getDistributionLogList,maijiToken is {}", maijiToken);
		AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, maijiToken, userInfoService);
		if (appUser == null) {
			logger.info("CapitalMainLogServiceImpl.getDistributionSumMoney,appUser is {}", JSON.toJSONString(appUser));
			return null;
		}
		Double sumMoney = distributionLogMapper.getDistributionSumMoney(appUser.getUuId(), param.getData().getLevel());

		return sumMoney;
	}

	@Override
	public DistributionLogListResDto getDistributionLogList(DistributionLogListReqDto param, String maijiToken) {
		logger.info("DistributionServiceImpl.getDistributionLogList,maijiToken is {}", maijiToken);
		AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, maijiToken, userInfoService);
		if(param.getData().getLevel() != CommonIntValueEnum.DISTRIBUTION_LOG_LEVEL_ONE.getValue() && param.getData().getLevel() != CommonIntValueEnum.DISTRIBUTION_LOG_LEVEL_TWO.getValue()) {
			return new DistributionLogListResDto(Status.PARAMETERERROR, "level参数必传 ");
		}
		
		if (appUser == null) {
			logger.info("CapitalMainLogServiceImpl.getcapitalIOList,appUser is {}", JSON.toJSONString(appUser));
			return new DistributionLogListResDto(Status.PARAMETERERROR, "token 无效 ");
		}
		Integer start = (param.getPage() - 1) * param.getSize();
		List<DistributionLogEntity> listDistributionLogEntity = distributionLogMapper
				.selectDistributionLogList(appUser.getUuId(), param.getData().getLevel(), start, param.getSize(),param.getData().getStartTime(),param.getData().getEndTime());

		List<DistributionLogListResData> list = new ArrayList<DistributionLogListResData>();
		for (DistributionLogEntity distributionLogEntity : listDistributionLogEntity) {
			DistributionLogListResData distributionLogListResData = new DistributionLogListResData();
			BeanUtils.copyProperties(distributionLogEntity, distributionLogListResData);

			ShopingOrder shopingOrder = shopingOrderMapper.selectById(distributionLogEntity.getOrderId());
			IdInputDto idInputDto = new IdInputDto();
			idInputDto.setId(shopingOrder.getUserId());
			// 获取用户信息
			BaseInputDto<IdInputDto> inputDto = new BaseInputDto<IdInputDto>();
			inputDto.setData(idInputDto);
			UserInfoResDto userInfoResDto = appLoginFeignService.getUserInfoWithUserId(inputDto);
			distributionLogListResData.setNickName(userInfoResDto.getData().getNickName());
			distributionLogListResData.setOrderStatus(shopingOrder.getStatus());
			distributionLogListResData.setHeadUrl(userInfoResDto.getData().getHeadUrl());
			list.add(distributionLogListResData);
		}
		DistributionLogListResDto distributionLogListResDto = new DistributionLogListResDto(Status.SUCCESS);

		distributionLogListResDto.setData(list);
		return distributionLogListResDto;
	}

	@Override
	@Async
	public void asyncDistributionFund(ShopingOrder shopingOrder) {
		logger.info("DistributionServiceImpl.asyncDistributionFund,orderId is {}", shopingOrder);
		// 购买商品的用户id
		String shopingOrderUserId = shopingOrder.getUserId();

		// 给上级用户分发分销基金
		BaseDataReqDto<String> param = new BaseDataReqDto<String>();
		param.setData(shopingOrderUserId);
		BaseDataResDto<AppUser> baseDataResDto = appLoginFeignService.getAppUer(param);
		AppUser appUser = baseDataResDto.getData();
		
		if (StringUtils.isBlank(appUser.getPid()) || (appUser.getEndTime() != null
                && new Date().getTime() > appUser.getEndTime().getTime())) return;

		// 上级信息
		param.setData(appUser.getPid());
		BaseDataResDto<AppUser> baseDataResDtoTwo = appLoginFeignService.getAppUer(param);
		if (baseDataResDtoTwo.getData() == null || baseDataResDtoTwo.getData().getIsCancel() == 1)return;
			
		// 一级用户分销提成比例
		DistributionFundRuleEntity oneDistributionFundRuleEntity = mongoTemplate.findOne(
				new Query(Criteria.where("level").is(CommonIntValueEnum.DISTRIBUTION_LOG_LEVEL_ONE.getValue())),
				DistributionFundRuleEntity.class, DistributionFundRuleEntity.TABLE_NAME);

		DistributionLogEntity distributionLogEntityOne = new DistributionLogEntity();
		distributionLogEntityOne.setUuId(UUID_MD5.getUUID());
		distributionLogEntityOne.setLevel(CommonIntValueEnum.DISTRIBUTION_LOG_LEVEL_ONE.getValue());
		distributionLogEntityOne.setInTime(new Date());
		Double money = Arith.multiplys(2, shopingOrder.getAmount(), oneDistributionFundRuleEntity.getPercentage());
		if(appUser.getRatio() != null) money = Arith.multiplys(2, shopingOrder.getAmount(), appUser.getRatio());
		distributionLogEntityOne.setMoney(money);
		distributionLogEntityOne.setUserId(appUser.getPid());
		distributionLogEntityOne.setOrderId(shopingOrder.getUuId());

		distributionLogMapper.insert(distributionLogEntityOne);
		CapitalMain capitalMain = capitalMainMapper.selectOneByUserId(appUser.getPid());
		capitalMain.setFrozenCapital(Arith.add(2, money, capitalMain.getFrozenCapital()));
		capitalMainMapper.updateById(capitalMain);

        // 修改订单信息，已经产生佣金
        shopingOrder.setCommission(true);
        shopingOrderMapper.updateById(shopingOrder);

		// 给上上级用户分发分销基金
		if (StringUtils.isBlank(baseDataResDtoTwo.getData().getPid())) return;

		// 二级用户分销提成比例
		DistributionFundRuleEntity twoDistributionFundRuleEntity = mongoTemplate.findOne(
				new Query(Criteria.where("level").is(CommonIntValueEnum.DISTRIBUTION_LOG_LEVEL_TWO.getValue())),
				DistributionFundRuleEntity.class, DistributionFundRuleEntity.TABLE_NAME);

		DistributionLogEntity distributionLogEntityTwo = new DistributionLogEntity();
		distributionLogEntityTwo.setUuId(UUID_MD5.getUUID());
		distributionLogEntityTwo.setLevel(CommonIntValueEnum.DISTRIBUTION_LOG_LEVEL_TWO.getValue());
		distributionLogEntityTwo.setInTime(new Date());
		Double twoMoney = Arith.multiplys(2, shopingOrder.getAmount(), twoDistributionFundRuleEntity.getPercentage());
		if(appUser.getRatio() != null) twoMoney = Arith.multiplys(2, shopingOrder.getAmount(), appUser.getRatio());
		distributionLogEntityTwo.setMoney(twoMoney);
		distributionLogEntityTwo.setUserId(baseDataResDtoTwo.getData().getPid());
		distributionLogEntityTwo.setOrderId(shopingOrder.getUuId());
		distributionLogMapper.insert(distributionLogEntityTwo);

		CapitalMain capitalMainTwo = capitalMainMapper.selectOneByUserId(baseDataResDtoTwo.getData().getPid());
		capitalMainTwo.setFrozenCapital(Arith.add(2, twoMoney, capitalMainTwo.getFrozenCapital()));
		capitalMainMapper.updateById(capitalMainTwo);
	}

	@Override
	@Async
	@Transactional(isolation = Isolation.READ_UNCOMMITTED)
	public void asyncReturnDistributionFund(String orderId) {
		logger.info("DistributionServiceImpl.asyncReturnDistributionFund,orderId is {}", orderId);
		// 查看该订单分配给上级用户的分销基金
		DistributionLogEntity distributionLogEntity = distributionLogMapper.getDistributionLogByOrderId(orderId,
				CommonIntValueEnum.DISTRIBUTION_LOG_LEVEL_ONE.getValue());
		if (distributionLogEntity == null) {
			return;
		}
		CapitalMain capitalMain = capitalMainMapper.selectOneByUserId(distributionLogEntity.getUserId());
		capitalMain
				.setFrozenCapital(Arith.subtract(2, capitalMain.getFrozenCapital(), distributionLogEntity.getMoney()));
		if (capitalMainMapper.updateById(capitalMain) <= 0) {
			asyncReturnDistributionFund(orderId);
		}
		// 修改产生的佣金表
		distributionLogEntity.setIsRefund(CommonIntValueEnum.DISTRIBUTION_LOG_LEVEL_ALREADYIS_REFUND.getValue());
		distributionLogMapper.updateById(distributionLogEntity);

		DistributionLogEntity distributionLogEntityTwo = distributionLogMapper.getDistributionLogByOrderId(orderId,
				CommonIntValueEnum.DISTRIBUTION_LOG_LEVEL_TWO.getValue());
		if (distributionLogEntityTwo == null) {
			return;
		}

		CapitalMain capitalMainTwo = capitalMainMapper.selectOneByUserId(distributionLogEntityTwo.getUserId());
		capitalMain.setFrozenCapital(
				Arith.subtract(2, capitalMainTwo.getFrozenCapital(), distributionLogEntityTwo.getMoney()));
		if (capitalMainMapper.updateById(capitalMainTwo) <= 0) {
			asyncReturnDistributionFund(orderId);
		}
		// 修改产生的佣金表
		distributionLogEntityTwo.setIsRefund(CommonIntValueEnum.DISTRIBUTION_LOG_LEVEL_ALREADYIS_REFUND.getValue());
		distributionLogMapper.updateById(distributionLogEntityTwo);
		return;
	}

	@Override
	public BaseDataResDto<List<DistributionFundRuleEntity>> getCommissionRate() {
		List<DistributionFundRuleEntity> list =  mongoTemplate.findAll(DistributionFundRuleEntity.class, DistributionFundRuleEntity.TABLE_NAME);
		BaseDataResDto<List<DistributionFundRuleEntity>> baseDataResDto = new BaseDataResDto<List<DistributionFundRuleEntity>>(Status.SUCCESS);
		baseDataResDto.setData(list);
		return baseDataResDto;
	}

	@Override
	public BaseDataResDto<DistributionAgentApplyInfoResData> getDistributionAgentApplyInfo(String maijiToken) {
        userInfoService.deleteAppUserByRedis(maijiToken);
		AppUser appUser = RedisUtil.getAppUserByRedis(redisTemplate, MyRedisConfig.REDISDATABASENO, maijiToken, userInfoService);
		DistributionAgentApplyEntity distributionAgentApplyEntity = selectById(appUser.getUuId());
		DistributionAgentApplyInfoResData resData = new DistributionAgentApplyInfoResData();
		if(distributionAgentApplyEntity != null) {
			BeanUtils.copyProperties(distributionAgentApplyEntity, resData);
            resData.setDistributionNum(appUser.getDistributionNum()).setIsApply(true).setRealName(realmName);
		}
		return new BaseDataResDto<DistributionAgentApplyInfoResData>(Status.SUCCESS).setData(resData);
	}

    @Override
    public BaseMetaResDto<List<DistributionAgentApplyInfoResData>> findAllDbApplyInfos(DbApplyInfoReqData data, ReqMetaData metaData) {
        EntityWrapper<DistributionAgentApplyEntity> entityWrapper = new EntityWrapper<>();
        String name = data.getName();
        if (StringUtil.isNotBlank(name)) entityWrapper.like("name", name);
        String phone = data.getPhone();
        if (StringUtil.isNotBlank(phone)) entityWrapper.like("phone", phone);
        String wxNum = data.getWxNum();
        if (StringUtil.isNotBlank(wxNum)) entityWrapper.like("wx_num", wxNum);
        Integer status = data.getStatus();
        if (status != null) entityWrapper.eq("status", status);
        entityWrapper.orderBy(data.getOrderBy(), data.getAsc());
        Page<DistributionAgentApplyEntity> page = selectPage(new Page<>(metaData.getPage(), metaData.getSize()), entityWrapper);
        List<DistributionAgentApplyEntity> dbApplyList = page.getRecords();
        List<DistributionAgentApplyInfoResData> dbApplyResList = Lists.newArrayList();
        if (dbApplyList.size() > 0) {
            List<String> userIds = dbApplyList.parallelStream().map(DistributionAgentApplyEntity::getUuId).collect(Collectors.toList());
            dbApplyResList = BaseService.dealWithOneToOne(dbApplyList,"getUuId", DistributionAgentApplyInfoResData.class,
                    "setUserInfo", userInfoService.selectList(userIds),"getUserId", UserInfo.class);
        }
        ResMetaData resMetaData = new ResMetaData(page.getCurrent(), page.getSize(), page.getTotal());
        return new BaseMetaResDto<List<DistributionAgentApplyInfoResData>>(Status.SUCCESS).setData(dbApplyResList).setResMetaData(resMetaData);
    }

    @Override
    public BaseResDto examineDbApply(DbApplyExamineReqData data) {
        DistributionAgentApplyEntity applyEntity = new DistributionAgentApplyEntity()
                .setUuId(data.getUuId()).setStatus(data.getStatus()).setExamineTime(new Date())
                .setOperatorId(data.getOperatorId()).setOperatorName(data.getOperatorName());
        if (! updateById(applyEntity)) return new BaseResDto(Status.ERROR);
        AppUser appUser = new AppUser().setUuId(data.getUuId()).setDistributionNum(ShareCodeUtil.random(6));
        if (! userInfoService.editAppUserById(appUser)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseDataResDto<Map<String, Double>> findDistributionCapitalCount () {
        EntityWrapper<CapitalMain> entityWrapper = new EntityWrapper<>();
        entityWrapper.setSqlSelect("sum(frozen_capital) frozen, sum(distribution_Money) distribution");
        Map<String, Object> mapObj = capitalMainService.selectMap(entityWrapper);
        HashMap<String, Double> map = Maps.newHashMap();
        Double frozen = (Double) mapObj.get("frozen");
        map.put("frozen", frozen);
        Double distribution = (Double) mapObj.get("distribution");
        map.put("distribution", distribution);
        map.put("sum", Arith.add(2, frozen, distribution));
        return new BaseDataResDto<Map<String, Double>>(Status.SUCCESS).setData(map);
    }

}
